﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RandomInitialSolution.cs" company="Luis de la Torre">
//   Copyright Luis de la Torre, unless otherwise indicated
// </copyright>
// <summary>
//   Defines the RandomInitialSolution type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace PVRP_SR
{
    using System;
    using System.Diagnostics;

    /// <summary>
    /// The random initial solution.
    /// </summary>
    public class RandomInitialSolution : ConstructionHeuristic
    {
        #region Public Methods and Operators

        /// <summary>
        /// The create solution.
        /// </summary>
        /// <param name="instance">
        /// The instance.
        /// </param>
        /// <returns>
        /// The <see cref="PvrpSrSolution"/>.
        /// </returns>
        public override PvrpSrSolution CreateSolution(TSPLIBParser instance)
        {
            PvrpSrSolution solution = new PvrpSrSolution(instance);
            solution.EmptySolution();
            RunRandomInitialSolution(solution);
            return solution;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The find insertion point.
        /// </summary>
        /// <param name="solution">
        /// The solution.
        /// </param>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <param name="vehicle">
        /// The node 1.
        /// </param>
        /// <param name="day">
        /// The node 2.
        /// </param>
        /// <returns>
        /// The <see cref="InsertionPoint"/>.
        /// </returns>
        private static InsertionPoint FindInsertionPoint(PvrpSrSolution solution, int node, int vehicle, int day)
        {
            // the insertion point of the node is at the end - after the predecessor of the end depot
            int insertionPredecessor = solution.Predecessors[day][vehicle][solution.Instance.StartDepots[0]];

            double insertionDistance = solution.InsertionDistance(node, day, insertionPredecessor, vehicle);
            double insertionCost = solution.InsertionCost(node, day, insertionPredecessor, vehicle);

            return new InsertionPoint(node, vehicle, insertionPredecessor, insertionCost, insertionDistance);
        }

        /// <summary>
        /// The run random initial solution.
        /// </summary>
        /// <param name="solution">
        /// The solution.
        /// </param>
        private static void RunRandomInitialSolution(PvrpSrSolution solution)
        {
            if (solution == null)
            {
                throw new ArgumentNullException("solution");
            }

            Debug.Assert(solution.Instance.StartDepots.Length == 1, "there should be one depot only");

            int[] customersRegular = new int[solution.Instance.NumNodesRegular];
            for (int i = 0; i < customersRegular.Length; i++)
            {
                customersRegular[i] = i + 1;
            }

            // shuffle the customers
            // Shuffler.Shuffle(customersRegular);
            Random generator = new Random();

            // randomly assign each customer to one of the vehicles
            foreach (int i in customersRegular)
            {
                int v = generator.Next(solution.Instance.NumVehicles);

                // insert the customer into the route of vehicle v on each day
                for (int t = 0; t < solution.Instance.NumDays; t++)
                {
                    if (solution.Instance.Demands[t][i] > 0)
                    {
                        solution.Insert(t, FindInsertionPoint(solution, i, v, t));
                    }
                }

#if DEBUG
                solution.PrintSolution();
#endif
            }

#if DEBUG
            solution.PrintSolution();
            Debug.Assert(solution.IsRouteFeasible(), "solution is infeasible");
#endif
        }

        #endregion
    }
}